package com.pwrd.minispring.spring.annotation.utils;

import java.io.File;
import java.io.FileFilter;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

/**
 * @Auther syc.
 * @Date 2016/10/25 10:59.
 */
public class ClassUtil {

    public static Set<Class<?>> getClassesByPackage(String packageName) {

        TreeSet<Class<?>> classSet = new TreeSet<>(Comparator.comparing(Class::getName));

        String[] packagePaths = initPaths();

        for (String packagePath : packagePaths) {

            findClassesInPackageByFile(packageName, packagePath, true, classSet);

        }

        return classSet;

    }

    /**
     * 以文件的形式来获取包下的所有Class
     *
     * @param packageName
     * @param packagePath 文件的绝对路径
     * @param recursive   是否迭代搜索包下的类
     */
    public static void findClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, Set<Class<?>> classes) {

        File[] dirfiles = findFilesInPackage(packageName, packagePath, recursive, ".class");

        if(dirfiles == null) {
            return;
        }

        // 循环所有文件
        for (File file : dirfiles) {
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                if(packageName == "") {
                    findClassesInPackageByFile(file.getName(), file.getAbsolutePath(), recursive, classes);

                } else {
                    findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
                }
            } else {
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    // 添加到集合中去
                    //classes.add(Class.forName(packageName + '.' + className));
                    //经过回复同学的提醒，这里用forName有一些不好，会触发static方法，没有使用classLoader的load干净
                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                } catch (ClassNotFoundException e) {

                    e.printStackTrace();
                }
            }
        }
    }

    private static File[] findFilesInPackage(String packageName, String packagePath, boolean recursive, String fileExtension) {
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);

        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            // log.warn("用户定义包名 " + packageName + " 下没有任何文件");
            return null;
        }

        // 如果存在 就获取包下的所有文件 包括目录
        File[] dirfiles = dir.listFiles(new FileFilter() {

            // 自定义过滤规则 如果可以循环(包含子目录) 否则是以.class结尾的文件(编译好的java类文件)
            public boolean accept(File file) {
                return (recursive && file.isDirectory())
                        || (file.getName().endsWith(fileExtension));
            }
        });

        return dirfiles;
    }

    /**
     * 初始化类根目录地址
     * @return
     */
    public static String[] initPaths() {
        try {
            String pathStr = System.getProperty("java.class.path");
            if(System.getProperty("os.name").startsWith("Windows")) {
                return pathStr.split(";");
            } else {
                return pathStr.split(":");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
